// Xampler, a MIDI-driven sampler
// Copyright (C) 2006 Nick Thomas
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA.

#include <math.h>
#include <samplerate.h>
#include <sndfile.h>
#include "Engine.hpp"
#include "Sample.hpp"
using namespace xampler;

Sample::Sample()
{
    m_number = 0;
    m_name = "";
    m_volume = DEFAULT_VOLUME;
    m_balance = 0.0;
    m_num_frames = 0;
    m_left_channel = 0;
    m_right_channel = 0;
}

bool Sample::load_data(Glib::ustring filename, Glib::ustring &error)
{
    // Open the file.
    SF_INFO sfinfo;
    sfinfo.format = 0;
    SNDFILE *sndfile = sf_open(filename.c_str(), SFM_READ, &sfinfo);
    int errnum;
    bool err = false;

    if (!sndfile) {
        error = "Could not open the file.";
        err = 1;
    }

    // Read the file data into a temporary buffer.
    float *file_data;
    if (!err) {
        file_data = new float[sfinfo.frames * sfinfo.channels];
        if (sf_readf_float(sndfile, file_data, sfinfo.frames) <
            sfinfo.frames) {
            error = "Read error.";
            err = true;
        }
    }

    // Perform sample rate conversion on the file data into a new
    // temporary buffer.
    SRC_DATA src_data;
    if (!err) {
        src_data.data_in = file_data;
        src_data.input_frames = sfinfo.frames;
        src_data.src_ratio =
            (double)g_sample_rate / (double)sfinfo.samplerate;
        src_data.output_frames =
            (int)ceil(src_data.src_ratio * sfinfo.frames);
        src_data.data_out = new float[src_data.output_frames];

        errnum = src_simple(&src_data, SRC_SINC_MEDIUM_QUALITY,
                            sfinfo.channels);
        if (errnum) {
            error = src_strerror(errnum);
            err = true;
        }

        delete [] file_data;
    }
    
    // Copy the resampled data into two non-interleaved buffers.
    float *new_left_channel, *new_right_channel;
    if (!err) {
        new_left_channel = new float[src_data.output_frames_gen];
        new_right_channel = new float[src_data.output_frames_gen];

        for (int i = 0; i < src_data.output_frames_gen; i++) {
            if (sfinfo.channels == 1) {
                new_left_channel[i] = new_right_channel[i] =
                    src_data.data_out[i * sfinfo.channels];
            } else {
                new_left_channel[i] = src_data.data_out[i * sfinfo.channels];
                new_right_channel[i] =
                    src_data.data_out[i * sfinfo.channels + 1];
            }
        }

        delete [] src_data.data_out;
    }

    // Replace the current sample data members with the new sample
    // data members, and deallocate the old ones.
    if (!err) {
        float *old_left_channel = m_left_channel;
        float *old_right_channel = m_right_channel;

        // Race condition in these three lines; see issue #10.
        m_num_frames = src_data.output_frames_gen;
        m_left_channel = new_left_channel;
        m_right_channel = new_right_channel;

        if (old_left_channel) {
            delete [] old_left_channel;
            delete [] old_right_channel;
        }

        m_filename = filename;
    }

    return !err;
}
